"""
作者：YxinMiracle
创作时间：2020/7/5
"""
import requests
import os
import re
from Crypto.Cipher import AES
from concurrent.futures import ThreadPoolExecutor
import sys

workers = ThreadPoolExecutor(max_workers=64)

if not os.path.exists('download'):
    os.makedirs('download')

# 正则表达式匹配规则
RULE = re.compile('v\.f\d+\.ts\?start=\d+&end=\d+&type=mpegts&sign=\w+&us=\d+&t=\w+|'
                  'v\.f\d+\.ts\?start=\d+&end=\d+&type=mpegts&sign=\w+&t=\w+&us=\d+|'
                  'v\.f\d+\.ts\?start=\d+&end=\d+&type=mpegts&t=\w+&sign=\w+&us=\d+|'
                  'v\.f\d+\.ts\?start=\d+&end=\d+&type=mpegts&t=\w+&us=\d+&sign=\w+|'
                  'v\.f\d+\.ts\?start=\d+&end=\d+&type=mpegts&us=\d+&t=\w+&sign=\w+|'
                  'v\.f\d+\.ts\?start=\d+&end=\d+&type=mpegts&us=\d+&sign=\w+&t=\w+')


class DownLoadTencentVideo(object):
    def __init__(self, m3u8_video_url):
        # 获取m3u8的视频url 这里专门是给腾讯课堂视频下载所用
        self.m3u8_video_url = m3u8_video_url
        # 请求得到m3u8的视频数据，将字符串拿去匹配
        self.m3u8_data = self.get_m3u8_data(m3u8_video_url)
        # 得到所有匹配到的字符串
        self.ts_files_end_str_list = self.get_ts_files_end_str_list
        # 得到基URL，拼接ts路由
        self.BASE_URL = "/".join(m3u8_video_url.split('?')[0].split('/')[:-1]) + "/"
        # 得到下载视频的路径
        self.download_path = os.getcwd() + r"\download2"
        # 将我们的私钥的URL，向量（偏移量）的到手
        self.URL_KEY, self.VI = re.findall('#EXT-X-KEY:METHOD=AES-128,URI="(.*?)",IV=(.*?)\n',
                                           self.m3u8_data)[0]
        # 初始化(加密模式CBC)
        """
        创建一个aes对象，就是这里的self.key
        cryptos.encrypt(text)  这是利用aes对象进行加密的方法 这里我们需要的是解密
        在下面进行解密，用：
        cryptos.decrypt(text)
        """
        self.key = AES.new(requests.get(self.URL_KEY).content,
                           # b'\xe6w\xb6\xaf\xf2\xfe?\xb9\xa4\xd5\x08[\xc1#=\x93' --> 这就是他的密钥的byte类型
                           AES.MODE_CBC,  # 定义模式 --> mode = AES.MODE_CBC
                           self.VI.replace("0x", "")[:16].encode()  # 偏移量--必须16字节
                           )  # 钥匙
        self.run()

    @classmethod
    def get_m3u8_data(cls, m3u8_vido_url):
        m3u8_data = requests.get(m3u8_vido_url).text
        return m3u8_data

    @property
    def get_ts_files_end_str_list(self):
        ts_files_end_str_list = re.findall(RULE, self.m3u8_data)
        return ts_files_end_str_list

    def download(self, key, url):
        print(
            f"the {key} file is downloading...... total files number is: {len(self.ts_files_end_str_list)}, now going {(int(key) / len(self.ts_files_end_str_list)) * 100}%")
        content_ts = requests.get(self.BASE_URL + str(url)).content
        with open(self.download_path + "\\" + str(int(key) + 1) + ".ts", 'ab') as f:
            f.write(self.key.decrypt(content_ts))  # 就是这里进行解密了
            f.flush()
            if int(key) + 1 == len(self.ts_files_end_str_list) - 1:  # 有bug 挺不住
                sys.exit()


    def run(self):
        print("11")
        for key, url in enumerate(self.ts_files_end_str_list):
            workers.submit(self.download, key, url)
        path = self.download_path
        os.popen('copy /b ' + path + '\\*.ts ' + path + '\\result.ts')

# def GetBkn(skey): # @81dka0shi
#     hash = 5381
#     for i in range(0, len(skey)):
#         hash += (hash << 5) + ord(skey[i])
#     return hash & 2147483647


if __name__ == '__main__':
    video_url = input("url:")
    download_obj = DownLoadTencentVideo(video_url)
    # print(GetBkn('@81dka0shi'))
    # with open("res.txt",'r') as fp:
    #     r = fp.read()
